package de.gis;

import java.io.File;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences.Editor;
import android.graphics.BitmapFactory;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

public class ImageLocator extends Activity {

	protected static final String DATABASE = "butterfly";
	private static final String TAG = "ButterflyActivity";
	// private static final String BASE_URL =
	// "http://192.168.1.115:5984/butterfly/";
	// private static final String LOCAL_BASE_URL =
	// "http://192.168.1.107:5984/";
	private static final String LOCAL_BASE_URL = "http://192.168.178.114:5984/";

	// private static final String REMOTE_BASE_URL = "http://78.47.21.51:5984/";
	private static final String REMOTE_BASE_URL = "http://192.168.178.114:5985/";
	private static final int PROGRESS_DIALOG = 0;
	private static final int CREDENTIALS_DIALOG = 1;
	private static final int EMPTY_DATABASE = 2;
	protected static final int CREDENTIALS_DIALOG_REMOTE = 3;
	private TextView status;
	private String db_url;
	private String[] tagSuggestions = new String[] { "Nature", "City" };

	enum replication_direction {
		TO_LOCAL, TO_REMOTE
	}

	enum CommState {
		OK, AUTH, AUTH_REMOTE, ERROR
	}

	// Define the Handler that receives messages from the thread and update the
	// progress
	final Handler handler = new Handler() {
		public void handleMessage(Message msg) {
			CommState state = CommState.valueOf(msg.getData()
					.getString("state"));
			try {
				dismissDialog(PROGRESS_DIALOG);
			} catch (IllegalArgumentException e) {
				// was not started, e.g when called from FetchTagSuggestions
			}
			switch (state) {
			case AUTH:
				showDialog(CREDENTIALS_DIALOG);
				break;
			case AUTH_REMOTE:
				showDialog(CREDENTIALS_DIALOG_REMOTE);
				break;
			case ERROR:
				Toast.makeText(
						getApplicationContext(),
						"Something went wrong: "
								+ msg.getData().getString("error"),
						Toast.LENGTH_LONG).show();
				break;
			case OK:
				Toast.makeText(getApplicationContext(),
						"Everything went fine.", Toast.LENGTH_SHORT).show();
				break;
			default:
				break;
			}
		}
	};
	private ProgressDialog progressDialog;
	private CommunicatorThread communicatorThread;
	private FetchTagSuggestions fetchTagSuggestions;

	private class CommunicatorThread extends Thread {

		Handler mHandler;
		private CouchCommunicator communicator;

		CommunicatorThread(Handler h, CouchCommunicator communicator) {
			mHandler = h;
			this.communicator = communicator;
		}

		public void run() {

			CommState state = CommState.OK;
			Bundle b = new Bundle();
			try {
				communicator.doit();
				// ImageLocator.this.documentDescription = null;
			} catch (UnauthorizedException uauth) {
				state = uauth.isLocal ? CommState.AUTH : CommState.AUTH_REMOTE;
			} catch (Exception ex) {
				// ImageLocator.this.documentDescription = null;
				Log.e(TAG, "Communication exception", ex);
				state = CommState.ERROR;
				b.putString("error", ex.getMessage());
			}
			Message msg = mHandler.obtainMessage();
			b.putString("state", state.toString());
			msg.setData(b);
			mHandler.sendMessage(msg);
		}

	}

	private void startUpload(DocumentDescription documentDescription) {
		Uploader uploader = new Uploader(db_url, getPreferences(MODE_PRIVATE),
				documentDescription);
		communicatorThread = new CommunicatorThread(handler, uploader);
		start();
	}

	private void startReplication(replication_direction direction) {
		Replicator replicator = new Replicator(LOCAL_BASE_URL, REMOTE_BASE_URL,
				direction, getPreferences(MODE_PRIVATE));
		communicatorThread = new CommunicatorThread(handler, replicator);
		start();
	}

	private void startCreatingDatabase() {
		DatabaseCreator creator = new DatabaseCreator(LOCAL_BASE_URL,
				getPreferences(MODE_PRIVATE));
		communicatorThread = new CommunicatorThread(handler, creator);
		start();
	}

	private void startFetchingSuggestions() {
		fetchTagSuggestions = new FetchTagSuggestions(db_url,
				getPreferences(MODE_PRIVATE));
		new CommunicatorThread(handler, fetchTagSuggestions).start();
	}

	private void restartCommunication() {
		if (communicatorThread == null) {
			return;
		}
		CouchCommunicator communicator = communicatorThread.communicator;
		communicator.initialize(getPreferences(MODE_PRIVATE));
		communicatorThread = new CommunicatorThread(handler, communicator);
		start();
	}

	private void start() {
		if (communicatorThread == null) {
			return;
		}
		communicatorThread.start();
		showDialog(PROGRESS_DIALOG);
	}

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		// TODO: remove HACK
		Editor editor = getPreferences(MODE_PRIVATE).edit();
		editor.putString(REMOTE_BASE_URL, "butterfly:btflypw");
		editor.commit();
		checkDbUrl();
		setMainView();
		startFetchingSuggestions();
	}

	private void checkDbUrl() {

		if (pingDB(LOCAL_BASE_URL)) {
			db_url = getFullUrl(LOCAL_BASE_URL);
			if (!pingDB(db_url)) {
				new AlertDialog.Builder(this)
						.setTitle("Local couchdb")
						.setMessage(
								"Create new Couch db? Afterward you can replicate the remote couch db (download)")
						.setCancelable(true).setNegativeButton("No",
								new DialogInterface.OnClickListener() {
									public void onClick(
											DialogInterface dialoginterface,
											int i) {
										db_url = null;
									}
								}).setPositiveButton("Go!",
								new DialogInterface.OnClickListener() {
									public void onClick(
											DialogInterface dialoginterface,
											int i) {
										startCreatingDatabase();
									}
								}).show();
			}
		}

		if (db_url == null && pingDB(REMOTE_BASE_URL)) {
			db_url = getFullUrl(REMOTE_BASE_URL);
		}
		if (db_url == null) {
			new AlertDialog.Builder(this).setTitle("No database available")
					.setMessage("Neither local nor remote couchdb available.")
					.setNegativeButton("Too bad",
							new DialogInterface.OnClickListener() {
								public void onClick(
										DialogInterface dialoginterface, int i) {
									// stop me;
								}
							}).show();
		}
		Log.i(TAG, "Using DB: " + db_url);

	}

	private String getFullUrl(String baseUrl) {
		return baseUrl + DATABASE + "/";
	}

	private boolean isUsingLocalDb() {
		return db_url != null && db_url.startsWith(LOCAL_BASE_URL);
	}

	public void setMainView() {
		setContentView(R.layout.main);
		Button set = (Button) findViewById(R.id.btn_take);
		set.setOnClickListener(new OnClickListener() {
			public void onClick(View view) {
				startFetchingSuggestions();
				// takePic();
				// emulator
				onActivityResult(0, 0, null);
			}
		});
		status = (TextView) findViewById(R.id.status);
		TextView txtDB = (TextView) findViewById(R.id.txt_db);
		txtDB.setText(db_url);
		Button rplDownload = (Button) findViewById(R.id.btn_repl_down);
		rplDownload.setOnClickListener(new OnClickListener() {
			public void onClick(View view) {
				startReplication(replication_direction.TO_LOCAL);
			}
		});
		rplDownload.setEnabled(isUsingLocalDb());
		Button rplUpload = (Button) findViewById(R.id.btn_repl_up);
		rplUpload.setOnClickListener(new OnClickListener() {
			public void onClick(View view) {
				startReplication(replication_direction.TO_REMOTE);
			}
		});
		rplUpload.setEnabled(isUsingLocalDb());
	}

	protected Dialog onCreateDialog(int id) {
		final String[] url = new String[] { db_url };
		switch (id) {
		case PROGRESS_DIALOG:
			progressDialog = ProgressDialog.show(ImageLocator.this, "",
					"Working hard ...", true);
			// progressDialog = new ProgressDialog(ImageLocator.this);
			// progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
			// progressDialog.setMessage("Uploading...");
			// progressDialog.setCancelable(false);
			return progressDialog;
		case CREDENTIALS_DIALOG_REMOTE:
			url[0] = REMOTE_BASE_URL;
		case CREDENTIALS_DIALOG:
			LayoutInflater factory = LayoutInflater.from(this);
			final View textEntryView = factory.inflate(
					R.layout.alert_dialog_text_entry, null);

			AlertDialog dialog = new AlertDialog.Builder(ImageLocator.this)
			// .setIcon(R.drawable.alert_dialog_icon)
					.setTitle("Provide credentials for " + url[0]).setView(
							textEntryView).setPositiveButton("OK",
							new DialogInterface.OnClickListener() {
								public void onClick(DialogInterface dialog,
										int whichButton) {
									EditText pwEdit = (EditText) textEntryView
											.findViewById(R.id.password_edit);
									EditText userEdit = (EditText) textEntryView
											.findViewById(R.id.username_edit);
									String both = userEdit.getText().toString()
											+ ":" + pwEdit.getText().toString();
									Editor editor = getPreferences(MODE_PRIVATE)
											.edit();
									editor.putString(url[0], both);
									editor.commit();
									restartCommunication();
								}
							}).setNegativeButton("Cancel",
							new DialogInterface.OnClickListener() {
								public void onClick(DialogInterface dialog,
										int whichButton) {
									communicatorThread = null;
								}
							}).create();
			return dialog;

		default:
			return null;
		}
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);

		try {
			final File dataFile = new File(getDir(), "sae.jpg");
			if (!dataFile.exists()) {
				// TODO: user notification
				return;
			}
			ExifInterface exifInterface = new ExifInterface(dataFile
					.getAbsolutePath());
			final float[] latLong = new float[2];
			exifInterface.getLatLong(latLong);
			String latlong = latLong[0] + ", " + latLong[1];
			Log.d(TAG, "Found coordinates: " + latlong);

			// switch layout
			setContentView(R.layout.send);
			ImageView imageView =  (ImageView) findViewById(R.id.imageThumbnail);
			imageView.setImageBitmap(BitmapFactory.decodeFile(dataFile.getAbsolutePath()));
			final AutoCompleteTextView txt_tag = (AutoCompleteTextView) findViewById(R.id.txt_tag);
			tagSuggestions = getTagSuggestions();
			// tagSuggestions = new String[] { getTagSuggestions()[0]};
			Log.d(TAG, tagSuggestions[0].getClass().getName());
			ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
					android.R.layout.simple_dropdown_item_1line, tagSuggestions);
			txt_tag.setThreshold(1);
			txt_tag.setAdapter(adapter);
			Button send = (Button) findViewById(R.id.btn_send);
			send.setOnClickListener(new OnClickListener() {

				public void onClick(View view) {
					setMainView();
					DocumentDescription documentDescription = new DocumentDescription(
							dataFile, latLong[0], latLong[1], txt_tag.getText());
					startUpload(documentDescription);
				}
			});
			TextView txt_latlong = (TextView) findViewById(R.id.txt_latlong);
			txt_latlong.setText(latlong);
		} catch (Exception e) {
			Log.e(TAG, e.getMessage());
		}

	}

	private void showInBrowser() {
		String url = db_url + "_design/butterfly/index.html";
		Intent i = new Intent(Intent.ACTION_VIEW);
		i.setData(Uri.parse(url));
		startActivity(i);
	}

	private String[] getTagSuggestions() {
		return fetchTagSuggestions.getSuggestions();
	}

	private void takePic() {
		// Display camera
		Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");

		// Specify file so that large image is captured and returned
		// TODO: What if there isn't any external storage?
		File photo = new File(getDir(), "sae.jpg");
		Uri uri = Uri.fromFile(photo);
		status.setText(uri.toString());
		intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, uri);
		// this.imageUri = Uri.fromFile(photo);

		startActivityForResult(intent, 1234);
	}

	private File getDir() {
		File dir = new File(Environment.getExternalStorageDirectory(),
				"butterfly");
		if (!dir.exists()) {
			boolean result = dir.mkdirs();
			if (!result) {
				Log.e(TAG, "Could not create directory: "
						+ dir.getAbsolutePath());
				return null;
			}
		}
		status.setText(dir.getAbsolutePath());
		return dir;
	}

	private boolean pingDB(String url) {
		Log.d(TAG, "Pinging db at " + url);
		try {
			new Ping(url, getPreferences(MODE_PRIVATE)).doit();
			return true;
		} catch (Exception ex) {
			Log.d(TAG, "Pinging failed", ex);
			return false;
		}
	}

}
